package com.xcity.game.battle.pve.template;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.xcity.game.battle.pve.PVEManager;
import com.xcity.game.battle.pve.StageBlockType;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.item.ItemInfo;
import com.xcity.game.item.drop.Drop;
import com.xcity.game.item.drop.impl.ExpDrop;
import com.xcity.game.item.drop.impl.GoldDrop;
import com.xcity.game.item.drop.impl.ItemDrop;
import com.xcity.game.npc.NpcTemplate;

import naga.x.App;
import naga.x.game.template.Template;
import naga.x.game.template.TemplateException;
import naga.x.game.template.TemplateService;
import naga.x.game.template.annotation.Excel;
import naga.x.util.NumberUtils;
import naga.x.util.StringUtils;

/**
 * 关卡
 * @author yang.li
 *
 */
@Excel(value = "stage.xlsx", sheet = 0)
public class StageTemplate extends Template {

	/** 类型（0：普通；1：boss关卡; 2:精英关） */
	protected byte type;
	
	/** 精英关 大关数 */
	protected byte page;

	/** 关卡名 */
	protected String name;
	
	/** 前置关ID */
	protected int previousStage;
	
	/** 描述 */
	protected String desc;
	
	/** 战斗背景图 */
	protected String bgImage;
	
	/** 关卡图标 */
	protected String icon;
	
	/** 剧情id */
	protected int plotId;
	
	/** 关卡色块(为空表示全部色块) */
	@Deprecated
	protected String blocks;
	@Deprecated
	protected int[] blocksArr;
	
	/** 角色发动一次攻击需要集齐的色块数 */
	@Deprecated
	protected int attackNeedBlockNum;

	/** 人物等级限制 */
	protected int levelLimit;

	/** 每日次数限制(-1表示不限制) */
	protected int numOfPerDay;
	
	/** 体力消耗 */
	protected int costStr;
	
	/** 敌方名称 */
	@Deprecated
	protected String enemyName;
	
	/** 敌方形象 */
	@Deprecated
	protected String enemyImage;
	
	/** 敌方攻击力 */
	@Deprecated
	protected int enemyAttack;
	
	/** 敌方攻击间隔(秒) */
	@Deprecated
	protected int enemyAttackCD;

	/** 敌方血量 */
	@Deprecated
	protected int enemyHP;

	/** 敌方免疫色块 */
	@Deprecated
	protected String invincibleBlocks;
	@Deprecated
	protected int[] invincibleBlocksArr;
	
	/** 可携带的道具 */
	@Deprecated
	protected String canCarryItems;
	@Deprecated
	protected List<ItemInfo> canCarryItemsList;

	/** 时间(秒) */
	protected int timeLimit;

	/** 步数 */
	@Deprecated
	protected int step;

	/** 消除(红、黄、蓝、绿、紫、橙)色块数量 */
	@Deprecated
	protected int[] clearBlocks;

	/** 通关奖励 */
	protected String[] passRewards;
	protected List<Drop>[] passRewardsDrop; // 按星级分组

	/** 胜利奖励 */
	protected String[] rewards;
	protected List<Drop> rewardsDrop;
	
	/** 地图信息 */
	protected String map;
	protected short[] mapData;
	
	/** 小怪id */
	protected int[] npcIds;
	protected NpcTemplate[] npcs;
//	protected int npcId;
//	protected NpcTemplate npc;
	
//	/** 小怪数量 */
//	protected int npcCount;
	
	/** boss id */
	protected int bossId;
	
	/** 关卡宝箱掉落组ID */
	protected int stageBoxId;

	/** 关卡宝箱坐标 */
	protected int[] boxPos;

	/** 关卡坐标 */
	protected int[] stagePos;
	
	/** 剩余血量 */
	protected int hpStar;
	
	/** 死亡数量 */
	protected int deathStar;
	
	/** 回合数 */
	protected int roundStar;
	
	/** 触发黑商概率 */
	protected int showShop;

	protected NpcTemplate boss;
	
	protected int fullStar;
	
	public static int MIN_ID = Integer.MAX_VALUE;
	public static final int STEP_NO_LIMIT = -1;
	public static StageTemplate FRESH_TEMPLATE; // 新手引导关卡
	public static final int CONDITION_COUNT = 4;
	public static int MAX_NORMAL_PAGE = 0; // 主线关卡总章节数

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public byte getType() {
		return type;
	}

	public void setType(byte type) {
		this.type = type;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getLevelLimit() {
		return levelLimit;
	}

	public void setLevelLimit(int levelLimit) {
		this.levelLimit = levelLimit;
	}

	public int getNumOfPerDay() {
		return numOfPerDay;
	}

	public void setNumOfPerDay(int numOfPerDay) {
		this.numOfPerDay = numOfPerDay;
	}

	@Deprecated
	public int getEnemyHP() {
		return enemyHP;
	}

	@Deprecated
	public void setEnemyHP(int enemyHP) {
		this.enemyHP = enemyHP;
	}

	@Deprecated
	public String getInvincibleBlocks() {
		return invincibleBlocks;
	}

	@Deprecated
	public void setInvincibleBlocks(String invincibleBlocks) {
		this.invincibleBlocks = invincibleBlocks;
	}

	@Deprecated
	public String getCanCarryItems() {
		return canCarryItems;
	}

	@Deprecated
	public void setCanCarryItems(String canCarryItems) {
		this.canCarryItems = canCarryItems;
	}

	@Deprecated
	public List<ItemInfo> getCanCarryItemsList() {
		return canCarryItemsList;
	}

	@Deprecated
	public void setCanCarryItemsList(List<ItemInfo> canCarryItemsList) {
		this.canCarryItemsList = canCarryItemsList;
	}
	
	@Deprecated
	public ItemInfo getCanCarryItem(int itemId) {
		List<ItemInfo> items = canCarryItemsList;
		for (int i = 0, size = items.size(); i < size; i++) {
			ItemInfo item = items.get(i);
			if (item.getId() == itemId) {
				return item;
			}
		}
		return null;
	}

	public int getTimeLimit() {
		return timeLimit;
	}

	public void setTimeLimit(int timeLimit) {
		this.timeLimit = timeLimit;
	}

	@Deprecated
	public int getStep() {
		return step;
	}

	@Deprecated
	public void setStep(int step) {
		this.step = step;
	}

	@Deprecated
	public int[] getClearBlocks() {
		return clearBlocks;
	}

	@Deprecated
	public void setClearBlocks(int[] clearBlocks) {
		this.clearBlocks = clearBlocks;
	}

	public String[] getPassRewards() {
		return passRewards;
	}

	public void setPassRewards(String[] passRewards) {
		this.passRewards = passRewards;
	}

	public String[] getRewards() {
		return rewards;
	}

	public void setRewards(String[] rewards) {
		this.rewards = rewards;
	}

	public String getBgImage() {
		return bgImage;
	}

	public void setBgImage(String bgImage) {
		this.bgImage = bgImage;
	}

	public String getIcon() {
		return icon;
	}

	public void setIcon(String icon) {
		this.icon = icon;
	}

	public int getPlotId() {
		return plotId;
	}

	public void setPlotId(int plotId) {
		this.plotId = plotId;
	}

	@Deprecated
	public String getBlocks() {
		return blocks;
	}

	@Deprecated
	public void setBlocks(String blocks) {
		this.blocks = blocks;
	}

	@Deprecated
	public int[] getBlocksArr() {
		return blocksArr;
	}

	@Deprecated
	public void setBlocksArr(int[] blocksArr) {
		this.blocksArr = blocksArr;
	}

	@Deprecated
	public int getAttackNeedBlockNum() {
		return attackNeedBlockNum;
	}

	@Deprecated
	public void setAttackNeedBlockNum(int attackNeedBlockNum) {
		this.attackNeedBlockNum = attackNeedBlockNum;
	}

	public int getCostStr() {
		return costStr;
	}

	public void setCostStr(int costStr) {
		this.costStr = costStr;
	}

	@Deprecated
	public String getEnemyName() {
		return enemyName;
	}

	@Deprecated
	public void setEnemyName(String enemyName) {
		this.enemyName = enemyName;
	}

	@Deprecated
	public String getEnemyImage() {
		return enemyImage;
	}

	@Deprecated
	public void setEnemyImage(String enemyImage) {
		this.enemyImage = enemyImage;
	}

	@Deprecated
	public int getEnemyAttack() {
		return enemyAttack;
	}

	@Deprecated
	public void setEnemyAttack(int enemyAttack) {
		this.enemyAttack = enemyAttack;
	}

	@Deprecated
	public int getEnemyAttackCD() {
		return enemyAttackCD;
	}

	@Deprecated
	public void setEnemyAttackCD(int enemyAttackCD) {
		this.enemyAttackCD = enemyAttackCD;
	}

	@Deprecated
	public int[] getInvincibleBlocksArr() {
		return invincibleBlocksArr;
	}

	@Deprecated
	public void setInvincibleBlocksArr(int[] invincibleBlocksArr) {
		this.invincibleBlocksArr = invincibleBlocksArr;
	}

	public List<Drop>[] getPassRewardsDrop() {
		return passRewardsDrop;
	}

	public void setPassRewardsDrop(List<Drop>[] passRewardsDrop) {
		this.passRewardsDrop = passRewardsDrop;
	}
	
	@Deprecated
	public List<Drop> getTheBestPassRewardDrop() {
		int i = passRewardsDrop.length - 1;
		return i >= 0 ? passRewardsDrop[i] : Collections.emptyList();
	}

	public List<Drop> getRewardsDrop() {
		return rewardsDrop;
	}

	public void setRewardsDrop(List<Drop> rewardsDrop) {
		this.rewardsDrop = rewardsDrop;
	}

	public String getMap() {
		return map;
	}

	public void setMap(String map) {
		this.map = map;
	}

	public short[] getMapData() {
		return mapData;
	}

	public void setMapData(short[] mapData) {
		this.mapData = mapData;
	}

//	public int getNpcId() {
//		return npcId;
//	}
//
//	public void setNpcId(int npcId) {
//		this.npcId = npcId;
//	}
//
//	public int getNpcCount() {
//		return npcCount;
//	}
//
//	public void setNpcCount(int npcCount) {
//		this.npcCount = npcCount;
//	}
	public int[] getNpcIds() {
		return npcIds;
	}

	public void setNpcIds(int[] npcIds) {
		this.npcIds = npcIds;
		this.npcs = null;
	}

	public int getBossId() {
		return bossId;
	}

	public void setBossId(int bossId) {
		this.bossId = bossId;
		this.boss = null;
	}

	public byte getPage() {
		return page;
	}

	public void setPage(byte page) {
		this.page = page;
	}
	
	public int getStageBoxId() {
		return stageBoxId;
	}

	public void setStageBoxId(int stageBoxId) {
		this.stageBoxId = stageBoxId;
	}

	public int getHpStar() {
		return hpStar;
	}

	public void setHpStar(int hpStar) {
		this.hpStar = hpStar;
	}
	
	public int getDeathStar() {
		return deathStar;
	}

	public void setDeathStar(int deathStar) {
		this.deathStar = deathStar;
	}
	
	public int getRoundStar() {
		return roundStar;
	}

	public void setRoundStar(int roundStar) {
		this.roundStar = roundStar;
	}
	
	public int[] getBoxPos() {
		return boxPos;
	}

	public void setBoxPos(int[] boxPos) {
		this.boxPos = boxPos;
	}

	public int[] getStagePos() {
		return stagePos;
	}

	public void setStagePos(int[] stagePos) {
		this.stagePos = stagePos;
	}

	public int getShowShop() {
		return showShop;
	}

	public void setShowShop(int showShop) {
		this.showShop = showShop;
	}

	public int getPreviousStage() {
		return previousStage;
	}

	public void setPreviousStage(int previousStage) {
		this.previousStage = previousStage;
	}

	//	public NpcTemplate getNpc() {
//		return npc != null ? npc : (npc = App.getApp().getServiceManager().get(TemplateService.class).get(NpcTemplate.class, npcId));
//	}
	public NpcTemplate[] getNpcs() {
		if (npcs == null && npcIds != null) {
			npcs = new NpcTemplate[npcIds.length];
			TemplateService service = App.getApp().getServiceManager().get(TemplateService.class);
			for (int i = 0; i < npcIds.length; i++) {
				NpcTemplate npc = service.get(NpcTemplate.class, npcIds[i]);
				npcs[i] = npc;
			}
		}
		return npcs;
	}
	
	public NpcTemplate getBoss() {
		return boss != null || bossId == 0 ? boss : (boss = App.getApp().getServiceManager().get(TemplateService.class).get(NpcTemplate.class, bossId));
	}
	
	public int getFullStar() {
		return fullStar;
	}

	@Override
	public void validate() throws TemplateException {
		if (id == 100000) {
			FRESH_TEMPLATE = this;
		} else if (id < MIN_ID) {
			MIN_ID = id;
		}
		if (step == 0) {
			step = STEP_NO_LIMIT;
		}
		blocksArr = NumberUtils.parseInts(blocks, ";", StageBlockType.ALL);
		blocks = null;
		invincibleBlocksArr = NumberUtils.parseInts(invincibleBlocks, ";", NumberUtils.EMPTY_INTS);
		invincibleBlocks = null;
		
		canCarryItemsList = parseItems(canCarryItems);
		canCarryItems = null;
		
		try {
			passRewardsDrop = parseStarRewardDrops(passRewards, false);
			passRewards = null;
//			rewardsDrop = parseStarRewardDrops(rewards, true)[0];
			rewardsDrop = parseRewardDrops(rewards, true)[0];
			rewards = null;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("stage.xlsx配置有误! id=" + id);
		}
		if(this.getPage() <= 0){//this.getType() == PVEManager.STAGE_TYPE_NORMAL && 
			throw new TemplateException("stage.xlsx page列配置有误! id=" + id);
		}
		
		int star = 1;
		int starCount = 0;
		if(hpStar > 0){
			star = star | (1 << 4);
			starCount++;
		}
		if(deathStar > -1 && deathStar < 6){
			star = star | (1 << 3);
			starCount++;
		}
		if(roundStar > 0){
			star = star | (1 << 2);
			starCount++;
		}
		if(timeLimit > 0){
			star = star | (1 << 1);
			starCount++;
		}
		if(starCount != 2){
			throw new TemplateException("stage.xlsx 评星配置有误! id=" + id);
		}
		fullStar = star;
		
		mapData = NumberUtils.parseShorts(map, ",", new short[0]);
		map = null;
		
		if ((getType() == PVEManager.STAGE_TYPE_NORMAL || getType() == PVEManager.STAGE_TYPE_BOSS)
				&& getPage() > MAX_NORMAL_PAGE) {
			MAX_NORMAL_PAGE = getPage();
		}
	}
	
	static List<Drop>[] parseStarRewardDrops(String[] rewards, boolean hasProbability) {
		List<List<Drop>> drops = new ArrayList<List<Drop>>();
		for (int i = 0; i < rewards.length; i += 3) {
			// 每3个为一组(现金、经验、物品)
			List<Drop> group = new ArrayList<Drop>();
			drops.add(group);
			int gold = NumberUtils.parseInt(rewards[i]);
			group.add(new GoldDrop(gold));
			
			if (i + 1 >= rewards.length) {
				break;
			}
			int exp = NumberUtils.parseInt(rewards[i + 1]);
			group.add(new ExpDrop(exp));
			
			if (i + 2 >= rewards.length) {
				break;
			}
			String items = rewards[i + 2];
			if (StringUtils.isNotEmpty(items)) {
				String[] strs = StringUtils.split(items, ";");
				for (String s : strs) {
					int dot = s.indexOf('=');
					int id = NumberUtils.parseInt(s.substring(0, dot));
					String suffix = s.substring(dot + 1);
					dot = suffix.indexOf(',');
					int count, probability;
					if (hasProbability || dot != -1) {
						probability = NumberUtils.parseInt(suffix.substring(0, dot));
						count = NumberUtils.parseInt(suffix.substring(dot + 1));
					} else {
						probability = GameStaticConfig.defaultChanceBase;
						count = NumberUtils.parseInt(suffix);
					}
//					if (dot < 0) {
//						probability = GameStaticConfig.defaultChanceBase;
//						count = NumberUtils.parseInt(suffix);
//					} else {
//						probability = NumberUtils.parseInt(suffix.substring(0, dot));
//						count = NumberUtils.parseInt(suffix.substring(dot + 1));
//					}
					group.add(new ItemDrop(probability, id, count));
				}
			}
		}
		return drops.toArray(new List[drops.size()]);
	}

	static List<Drop>[] parseRewardDrops(String[] rewards, boolean hasProbability) {
		List<List<Drop>> drops = new ArrayList<List<Drop>>();
		List<Drop> group = new ArrayList<Drop>();
		drops.add(group);
		int size = rewards.length;
		if(size > 0){
			int gold = NumberUtils.parseInt(rewards[0]);
			group.add(new GoldDrop(gold));
		}
		if(size > 1){
			int exp = NumberUtils.parseInt(rewards[1]);
			group.add(new ExpDrop(exp));
		}
		if(size > 2){
			for (int i = 2; i < size; i++) {
				int dot = rewards[i].indexOf('=');
				int id = NumberUtils.parseInt(rewards[i].substring(0, dot));
				String[] subStrs = StringUtils.split(rewards[i].substring(dot + 1), ",");
				int count, count2, probability;
				int lenth = subStrs.length;
				if(lenth == 3){
					probability = NumberUtils.parseInt(subStrs[0]);
					count = NumberUtils.parseInt(subStrs[1]);
					count2 = NumberUtils.parseInt(subStrs[2]);
				}else if(lenth == 2){
					if(hasProbability){
						probability = NumberUtils.parseInt(subStrs[0]);
						count = NumberUtils.parseInt(subStrs[1]);
						count2 = count;
					}else{
						probability = GameStaticConfig.defaultChanceBase;
						count = NumberUtils.parseInt(subStrs[0]);
						count2 = NumberUtils.parseInt(subStrs[1]);
					}
				}else{
					probability = GameStaticConfig.defaultChanceBase;
					count = NumberUtils.parseInt(subStrs[0]);
					count2 = count;
				}
				group.add(new ItemDrop(probability, 0, id, count, count2));
			}
		}
		return drops.toArray(new List[drops.size()]);
	}
	
	static List<ItemInfo> parseItems(String s) {
		if (StringUtils.isEmpty(s)) {
			return Collections.emptyList();
		}
		String[] strs = StringUtils.split(s, ";");
		List<ItemInfo> items = new ArrayList<ItemInfo>(strs.length);
		for (String str : strs) {
			int dot = str.indexOf('=');
			int id = NumberUtils.parseInt(str.substring(0, dot));
			int count = NumberUtils.parseInt(str.substring(dot + 1));
			ItemInfo item = new ItemInfo(id, count);
			items.add(item);
		}
		return items;
	}
	
}
